/* 简介：cothread 是一个轻量级协程调度器，由纯C语言实现，易于移植到各种单片机。
 * 同时，由于该调度器仅仅运行在一个实际线程中，所以它也适用于服务器高并发场景。
 *
 * 版本: 1.0.0   2019/02/25
 *
 * 作者: 覃攀 <qinpan1003@qq.com>
 *
 */

#ifndef COTHREAD_H_
#define COTHREAD_H_

#define COTHREAD_NR (OS_THREAD_NR)
#define COEVENT(n) (1 << n)
#define COEVENT_CLR(n) do{ccb->event_signaled &= ~(1 << n);}while(0)

enum cothread_status {
    COTHREAD_STATUS_NONE = 0,
    COTHREAD_STATUS_READY = 1,
    COTHREAD_STATUS_DELAY = 2,
    COTHREAD_STATUS_WAIT = 3,
};

#define coresult_t int
#define STATUS_CONTINUE 0
#define STATUS_DONE     0xff

#define IRQ_HANDLE_CONTINUE (0)
#define IRQ_HANDLE_DONE (1)

/* 最多 32 个 irq */
enum IRQ_HANDLE_NUMBER {
    IRQ_HANDLE_UART = 0,
    IRQ_HANDLE_MAX = 32,
};

typedef int cothread_prio_t;

typedef struct cothread_control_block {
    coresult_t (*fun)(struct cothread_control_block *ccb);
    cothread_prio_t prio;
    void *arg;
    unsigned int ret_addr;
    enum cothread_status status;
    unsigned int event_mask;        /* 等待的事件 */
    unsigned int event_signaled;    /* 已到达的事件 */
    unsigned int event_wakeup;      /* 1事件唤醒，0超时唤醒 */
    unsigned int timeout_tick;      /* 到达超时的 tick */
    struct cothread_control_block *prev;
    struct cothread_control_block *next;
}ccb_t;

ccb_t *current_thread;

#define EVENT_DATA (1)
#define EVENT_READY (2)
#define EVENT_MQ_ARRIVE (3)

#define time_before(a,b) ((a) - (b) >= (1 << 31))
void system_tick(void);
int cothread_init(void);
void cothread_loop_once(void);
void cothread_start(void);
ccb_t *cothread_create(coresult_t (*fun)(ccb_t *ccb), void *arg, cothread_prio_t prio);
int cothread_delete(ccb_t *ccb);
void cothread_yeild(ccb_t *ccb);
int cothread_sleep(ccb_t *ccb, unsigned int tick);
int cothread_wait(ccb_t *ccb, unsigned int event_mask, unsigned int tick);
int cothread_signal(ccb_t *ccb, unsigned int event_mask);
unsigned int get_system_tick(void);
void cothread_show_stat(void);

/* 注册 idle 任务钩子函数，用于对优先级无要求的场景 */
int register_idle_hook(void (*hook)(void));

/* 注册任务调度钩子函数，用于对优先级要求最高，能及时响应中断的场景 */
int register_sched_hook(void (*hook)(void));

/* 
通过   switch-case 宏定义来模拟 OS 的线程调度

注意：1、OS调度函数（yeild,delay,wait,delete）只能用在线程主函数中,create,signal可以用在子函数中。
      2、线程主函数中，可以嵌套使用 while for if，不能使用 switch-case 。
      3、线程子函数中，可以嵌套使用 while for if switch-case 。
      
所以：1、主函数可以用 if-else 、查表法、或者子函数辅助实现 switch-case 控制逻辑。
      2、子函数内部不能阻塞（因为不能用OS调度函数）。
      
备注：   如果使用 GCC 的goto跳转行号 替换 switch-case，则主函数可以支持 switch-case嵌套
*/
/*---------------------------------------------------------------------------*/
/* 线程主函数头部宏 */
/* 使用特殊的变量 __unique_ccb，可以防止 yeild,sleep,wait,delete 放入子函数(编不过) */
#define thread_start()\
ccb_t *__unique_ccb=ccb;\
switch (__unique_ccb->ret_addr)\
    {\
        case 0:

/* 线程在同等优先级之间让出CPU，如果此时有其他同等优先级线程就绪则调度其他线程，否则继续调度当前线程 */
#define thread_yeild()\
do{__unique_ccb->ret_addr = __LINE__;cothread_yeild(__unique_ccb);return STATUS_CONTINUE;case __LINE__:;}while(0)

/* 线程休眠 */
#define thread_sleep(tick)\
do{__unique_ccb->ret_addr = __LINE__;cothread_sleep(__unique_ccb, tick);return STATUS_CONTINUE;case __LINE__:;}while(0)

/* 线程休眠等待信号，可以设置超时时间，0表示永远等待 */
#define thread_wait(event,tick)\
do{__unique_ccb->ret_addr = __LINE__;cothread_wait(__unique_ccb, event, tick);return STATUS_CONTINUE;case __LINE__:;}while(0)

/* 线程删除自己 */
#define thread_delete()\
do{return STATUS_DONE;}while(0)

/* 线程主函数尾部宏 */
#define thread_end()\
        default:\
            return STATUS_DONE;\
    }

/*---------------------------------------------------------------------------*/

#endif // COTHREAD_H_

